#include "game.h"
#include "Balloon.h"
#include "ASprite.h"
#include "Box2D.h"
#include "Font.h"
#include "ParticleSystem/ParticleHolder.h"
#include "ParticleSystem/ParticleHolderManager.h"

#define MOVE_STEP TIME_STEP




Balloon::Balloon()
{
	SetObjectType(Object_Balloon);	

	//m_sprite = GetResManager()->getSprite(SPRITE_BOTTLE);
	DisableMovement();
	m_radius = 32;


	SetObjectType(Object_Balloon);
	m_electricEffect = NULL;	
	m_flags.Enabled = false;
}

void Balloon::SaveData(CWriteFile* stream)
{
	GameObject::SaveData(stream);

	stream->WriteS32(m_beginPointX);
	stream->WriteS32(m_beginPointY);
	stream->WriteS32(m_controlPointX);
	stream->WriteS32(m_controlPointY);
	stream->WriteS32(m_targetPointX);
	stream->WriteS32(m_targetPointY);

	stream->WriteF32(m_lastSpeed.X);
	stream->WriteF32(m_lastSpeed.Y);
	stream->WriteF32(m_Speed.X);
	stream->WriteF32(m_Speed.Y);
	stream->WriteF32(m_displacement.X);
	stream->WriteF32(m_displacement.Y);
	stream->WriteF32(m_lastCollisionPoint.X);
	stream->WriteF32(m_lastCollisionPoint.Y);
	stream->WriteF32(m_closestPoint.X);
	stream->WriteF32(m_closestPoint.Y);
	stream->WriteS32(m_state);

	stream->WriteS8(m_bIsMovementEnabled);

	stream->WriteS32(m_radius);
	stream->WriteU32(m_color);

}
void Balloon::LoadData(CReadFile* stream)
{
	GameObject::LoadData(stream);

	m_beginPointX = stream->ReadS32();
	m_beginPointY = stream->ReadS32();
	m_controlPointX = stream->ReadS32();
	m_controlPointY = stream->ReadS32();
	m_targetPointX = stream->ReadS32();
	m_targetPointY = stream->ReadS32();

	m_lastSpeed.X = stream->ReadF32();
	m_lastSpeed.Y = stream->ReadF32();
	m_Speed.X = stream->ReadF32();
	m_Speed.Y = stream->ReadF32();
	m_displacement.X = stream->ReadF32();
	m_displacement.Y = stream->ReadF32();
	m_lastCollisionPoint.X = stream->ReadF32();
	m_lastCollisionPoint.Y = stream->ReadF32();
	m_closestPoint.X = stream->ReadF32();
	m_closestPoint.Y = stream->ReadF32();
	m_state = stream->ReadS32();

	m_bIsMovementEnabled = stream->ReadS8();

	m_radius = stream->ReadS32();
	m_color = stream->ReadU32();
}

void Balloon::Load(IAttributes* attr)
{
	
}

void Balloon::InitEffect()
{
	m_electricEffect = GL_NEW ParticleHolder("Effect1");
	m_electricEffect->SetSelfManagement(false);
	m_electricEffect->SetVisible(true);

	ParticleHolderManager::Add(m_electricEffect);
	m_electricEffect->SetPosition(m_physicsBody->GetPosition().x,m_physicsBody->GetPosition().y,true);
}

void Balloon::SetNature(int nature) 
{
	if(m_nature != nature)
	{
		m_nature = nature;
		if(m_nature == GREEN_NATURE)
			InitEffect();
		else
		{
			ParticleHolderManager::Remove(m_electricEffect);
			SAFE_DELETE(m_electricEffect);
			m_electricEffect = NULL;
		}
	}
		
}

void Balloon::SetEnabled( bool v )
{
	if(v != m_flags.Enabled)
	{
		m_flags.Enabled = v;
		if(v)
		{
			SetState(BALL_STATE_IDLE);
			SetPosition(START_BALL_X,START_BALL_Y);
			SetNoDisplacement();
			InitPhysics();
			m_lifeTimer.SetEnable(false);
			m_bounceCount = 0;

			if(m_nature == RED_NATURE)
			{
				InitEffect();
			}
		}
		else
		{
			if(m_physicsBody)
				GetGameObjectManager()->GetPhysicsWorld().DestroyBody(m_physicsBody);
			m_physicsBody = NULL;
			if(GetItemManager()->GetCurrentBall() == this)
			{
				GetItemManager()->SetCrtBalloon(-1);
			}

			if(m_nature == GREEN_NATURE)
			{
				m_electricEffect->StopEmitter();
				m_electricEffect->SetSelfManagement(true);
				m_electricEffect = NULL;
			}
		}
		
	}

}

void Balloon::Draw()
{
	//m_sprite->PaintFrame(0,m_position.X,m_position.Y);
	
	//g2DCommRI.tex = (TexInfo*)getTexMgr()->GetTex(0);
	//getGfx()->Flush2D();
	

	getGfx()->SetColor(m_color);	
	//getGfx()->DrawCircle2(m_position.X,m_position.Y,m_radius);

#if (SHOW_BOUND_RECT)
	getGfx()->SetColor(0xff00ff00);	
	getGfx()->DrawRect(m_boundingbox->left,
		m_boundingbox->top,
		m_boundingbox->GetWidth(),
		m_boundingbox->GetHeight());
#endif

	getGfx()->SetColor(0xffff0000);		
	/*if(CanMove())
	{
		getGfx()->DrawLine(m_position.X,m_position.Y,m_lastCollisionPoint.X,m_lastCollisionPoint.Y);
	}*/

	/*line2df line1 = line2df(745,484,753,484);
	line2df line2 = line2df(100,600,600,100);
	
	getGfx()->SetColor(0xff0000ff);	
	getGfx()->DrawCircle2(m_closestPoint.X,m_closestPoint.Y,6);*/
	
	char buff[32];
	switch (m_nature)
	{
	case RED_NATURE:
		sprintf(buff,"Red");
		break;
	case GREEN_NATURE:
		sprintf(buff,"Green");
		break;
	case BLUE_NATURE:
		sprintf(buff,"Blue");
		break;
	case CYAN_NATURE:
		sprintf(buff,"Cyan");
		break;
	case MAGENTA_NATURE:
		sprintf(buff,"Magetan");
		break;
	case YELLOW_NATURE:
		sprintf(buff,"Yellow");
		break;
	}
	
	ASprite* balloon = GetResManager()->getSprite(SPRITE_ELECTRIC);
	balloon->PaintAndUpdateCurrentAnimation(0,m_physicsBody->GetPosition().x,m_physicsBody->GetPosition().y);

	getFont()->DrawText2((GL_TCHAR*)buff,m_physicsBody->GetPosition().x,m_physicsBody->GetPosition().y);

}

void Balloon::Update()
{
	GameObject::Update();
	

}

void Balloon::Initialize()
{
	SetState(BALL_STATE_IDLE);
	
	//ReCalBoundingBox();
	//InitPhysics();
}


void Balloon::InitPhysics()
{	
	{
		b2CircleDef circleDef;
		circleDef.radius = 0.3f;
		circleDef.density = 0.00001f;
		circleDef.restitution = 1.0f;
		circleDef.friction = 0;



		b2BodyDef bd;
		bd.allowSleep = false;
		bd.position.Set(0.5f, 0.3f);
		bd.gravityFactor  =0.0f;
		m_physicsBody = GetGameObjectManager()->GetPhysicsWorld().CreateBody(&bd);
		
		m_physicsBody->CreateShape(&circleDef);
		m_physicsBody->SetMassFromShapes();

		m_physicsBody->SetUserData( this );
	}
}
void Balloon::SetPath(float cx,float cy, float ex, float ey)
{
	//m_position.X = 0.5f;
	//m_position.Y = 0.3f;

	m_beginPointX = 0.5f;//m_position.X;
	m_beginPointY = 0.3f;//m_position.Y;
	m_controlPointX = cx;
	m_controlPointY = cy;
	m_targetPointX = ex;
	m_targetPointY = ey;
	EnableMovement();
	m_stepBenzier = 0;
	SetState(BALL_STATE_CURVE);

	if(m_targetPointX-m_controlPointX == 0 && m_targetPointY-m_controlPointY == 0)
		m_Speed = vector2df(m_targetPointX-m_beginPointX,m_targetPointY-m_beginPointY);
	else
		m_Speed = vector2df(m_targetPointX-m_controlPointX,m_targetPointY-m_controlPointY);
	m_Speed.normalize();


	m_physicsBody->AllowSleeping(false);

	m_bounceCount = 0;
	switch (m_nature)
		{
		case RED_NATURE:
			m_damage = 100;
			m_rebounds = 1;
			break;
		case GREEN_NATURE:
			m_damage = 50;
			m_rebounds = 10;
			break;
		case BLUE_NATURE:
			m_damage = 1;
			m_rebounds = -1;
			break;
		case CYAN_NATURE:
			m_damage = 100;
			m_rebounds = -1;
			break;
		case MAGENTA_NATURE:
			m_damage = 100;
			m_rebounds = -1;
			break;
		case YELLOW_NATURE:
			m_damage = 100;
			m_rebounds = 10;
			break;
		}	
	
}

void Balloon::Update_PreCollision()
{
	if ( m_physicsBody )
	{
		b2Vec2 spd = m_physicsBody->GetLinearVelocity();
		if ( spd.LengthSquared() > 0 )
		{
			
			if(m_state == BALL_STATE_BACK)
			{
				b2Vec2 newSpeed = b2Vec2(this->m_refItem->getCenterX(),this->m_refItem->getCenterY()) - m_physicsBody->GetPosition();
				
				if(m_lifeTimer.GetTime() < getGame()->GetGameplayTimeStep())				
				{
					int gfgf=0;
				}
				newSpeed.Normalize();
				newSpeed *= GetSpeed();	//8m/s
			}
			//else
			{
				spd.Normalize();
				spd *= GetSpeed();	//8m/s
			}

		}
		m_physicsBody->SetLinearVelocity( spd );
		
	}

	if(CanMove())
	{ 		
		CompDisplacement();
	}
}
void Balloon::Update_PostCollision()
{
	if ( ! m_physicsBody )
	{
		return;
	}

	if(m_state == BALL_STATE_CURVE)
	{
		if(m_collisionList.size() >0)
		{
			SetState(BALL_STATE_MOVING);
		}
	}
	else if(m_state == BALL_STATE_MOVING)
	{
		for(int i = 0;i<m_collisionList.size();i++)
		{
			GameObject* h = m_collisionList[i].obj;

			if ( h->GetObjectType() == Object_Robot)
			{
				//SetState(BALL_STATE_BACK);
				//b2Vec2 newSpeed = b2Vec2(this->m_refItem->getCenterX(),this->m_refItem->getCenterY()) - m_physicsBody->GetPosition();			
				//m_lifeTimer.SetTime(newSpeed.Length() / (GetSpeed()));
				//m_lifeTimer.SetEnable(true);

				//newSpeed.Normalize();
				//newSpeed *= GetSpeed();	//8m/s
				//m_physicsBody->SetLinearVelocity(newSpeed);
				//GetGameObjectManager()->GetPhysicsWorld().DestroyBody(m_physicsBody);
				//m_physicsBody = NULL;
				
				//this->m_refItem->
				//h->TakeDamage(m_damage);
			}

			
		}

		if(m_collisionList.size() > 0)
		{
			m_bounceCount++;
			if ( m_bounceCount > m_rebounds )	
			{
				SetEnabled(false);
				UnSpawn();
			}
		}
	}
	/*else if(m_state == BALL_STATE_BACK)
	{
		m_lifeTimer.Update(getGame()->GetGameplayTimeStep());
		if(m_lifeTimer.IsDone())
		{
			SetEnabled(false);
		}
	}*/

	if(IsEnabled() && (m_nature & BLUE_NATURE) != 0)
	{
		if(m_physicsBody->GetPosition().x<0 ||m_physicsBody->GetPosition().x> TALL_BY_METERS*RATIO_SCREEN ||
			m_physicsBody->GetPosition().y<0 || m_physicsBody->GetPosition().y > TALL_BY_METERS)
		{
			SetEnabled(false);
		}
	}

	if(m_electricEffect)
		m_electricEffect->SetPosition(m_physicsBody->GetPosition().x,m_physicsBody->GetPosition().y);

}


bool Balloon::ShouldCollideWith( GameObject* h )
{
	if(m_state == BALL_STATE_BACK)
		return false;
	if(h && h->GetObjectType() == Object_Balloon)
		return false;

	if((m_nature & BLUE_NATURE) != 0)
	{
		return false;
	}


	return true;
}

void Balloon::SetNoDisplacement()
{
	m_Speed.set(0, 0);
	m_displacement.set(0, 0);
}

void Balloon::CompDisplacement()
{
	if(m_state == BALL_STATE_CURVE)
	{
		float t = m_stepBenzier;
		float step = 0.01f;
		float tdir = 0;
		float sx,sy,ex,ey;

		b2Vec2 pos = m_physicsBody->GetPosition();
		sx = pos.x;
		sy = pos.y;
			
		float speed = getGame()->GetGameplayTimeStep() * GetSpeed();
		while(t<=1)
		{
			t+=step;
			ex = (1-t)*(1-t)*m_beginPointX + 2*(1-t)*t*m_controlPointX + t*t*m_targetPointX;
			ey = (1-t)*(1-t)*m_beginPointY + 2*(1-t)*t*m_controlPointY + t*t*m_targetPointY;

			float dir = sqrt((float)((ex-sx)*(ex-sx) + (ey-sy)*(ey-sy)));
			if(abs(tdir + dir - speed)<0.01f)
			{
				m_displacement.X = ex - pos.x;
				m_displacement.Y = ey - pos.y;
				m_stepBenzier = t;
				break;
			}
			else
			{
				if(tdir+dir < speed)
				{
					tdir += dir;
					sx = ex;
					sy = ey;
				}
				else
				{
					t-=step;
					step/=2;
				}
			}

						
		}
		//float t = m_step/(m_maxStep * 1.0f);
		//m_displacement.X = (1-t)*(1-t)*m_beginPointX + 2*(1-t)*t*m_controlPointX + t*t*m_targetPointX - m_position.X;
		//m_displacement.Y = (1-t)*(1-t)*m_beginPointY + 2*(1-t)*t*m_controlPointY + t*t*m_targetPointY - m_position.Y;
		if(t >=1)
		{
			m_state++;
		}
		//m_lastCollisionPoint = m_position + m_displacement;

		b2Vec2 spd(m_displacement.X,m_displacement.Y);
		/*b2Vec2 abc = ConvertScreenToWorld(m_position.X,m_position.Y);
		b2Vec2 xyz = ConvertScreenToWorld(m_lastCollisionPoint.X,m_lastCollisionPoint.Y);
		spd *= (TALL_BY_METERS/(SCREEN_HEIGHT*1.0f));
		spd = (xyz-abc);*/
		spd *= (1/getGame()->GetGameplayTimeStep());
		//b2Vec2 spd(0.1,0.1);
		m_physicsBody->SetLinearVelocity( spd );
	}
	else if(m_state == BALL_STATE_MOVING)
	{
		b2Vec2 spd(m_Speed.X,-m_Speed.Y);
		spd.Normalize();
		spd *= MOVE_STEP;
		//m_physicsBody->SetLinearVelocity( spd );
		m_displacement = MOVE_STEP*m_Speed;
	}
	else if(m_state == BALL_STATE_BACK)
	{
		m_displacement = m_Speed;
	}
}